﻿using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace DKE_Kinect.Entwicklung.Grafik.ControlManaging
{


	/// <summary>
	/// A menu für quick access to important features
	/// </summary>
	public class QuickMenu : Control, IMenu<QuickMenuItem>
	{
		// Readonyl - Fields
		private readonly int pPies = 6;
		private readonly Point[] pPositions = new Point[] { new Point(198, 0), new Point(466, 63), new Point(466, 378), new Point(201, 529), new Point(0, 383), new Point(0, 69) };
		private readonly Rectangle[] pIconBounds = new Rectangle[]
		{
			new Rectangle(115,48,120,120),
			new Rectangle(89,124,120,120),
			new Rectangle(89,67,120,120),
			new Rectangle(115,60,120,120),
			new Rectangle(74,67,120,120),
			new Rectangle(74,124,120,120),
		};

		private readonly Point pStandardSize = new Point(749, 757);

		// Controls
		private Button pPrevButton;
		private Button[] pButtons;
		private Control pHint;

		// Sub Menu Properties
		private int pCollapsedIndex;
		private int pSelectedIndex;
		private IMenu<QuickMenuItem> pActiveMenu;
		private List<QuickMenuItem> pSubItems;

		private bool pChangeLayer;

		/// <summary>
		/// Instanziiert ein neues Objekt dieser Klasse.
		/// </summary>
		/// <param name="Owner">Gibt den übergeordneten Container an.</param>
		public QuickMenu (ContainerManager Owner)
			: base("QuickMenu")
		{
			if (Owner == null)
				throw new NullReferenceException();

			base.Parent = Owner;
			this.Size = this.pStandardSize;

			this.pSubItems = new List<QuickMenuItem>();

			this.pButtons = new Button[this.pPies];
			for (int i = 0; i < this.pPies; i++)
			{
				this.pButtons[i] = new Button("QM" + i.ToString(), ButtonType.QuickMenuStatic, i);
				this.pButtons[i].Text = string.Empty;
				this.pButtons[i].Parent = this;
				this.pButtons[i].Location = this.pPositions[i];
				this.pButtons[i].Visible = false;

				this.pButtons[i].IconAlpha = 0.75f;
				this.pButtons[i].IconBounds = this.pIconBounds[i];
			}

			this.pHint = new Control("Hint", ContainerRessources.GetLabel());
			this.pHint.Visible = false;
			this.pHint.Parent = this;
			this.pHint.Location = new Point(216, 345);

			this.pCollapsedIndex = -1;
			this.pSelectedIndex = -1;
			this.pActiveMenu = this;

			this.pChangeLayer = false;
		}

		#region Properties

		/// <summary>
		/// Gibt an, welche Art der Aktion hinter dem Menüpunkt steckt.
		/// </summary>
		public ActivationType ActivationType { get { return ActivationType.LayerForward; } }

		/// <summary>
		/// Gibt den Index dieses Menüpunktes gegenüber dem übergeordneten Menü an.
		/// </summary>
		public int Index { get { return -1; } }

		/// <summary>
		/// Gibt an, welcher Untermenüpunkt dieses Menüpunktes ausgewählt wurde oder legt diesen fest.
		/// </summary>
		public int SelectedIndex
		{
			get { return this.pSelectedIndex; }
			set
			{
				if ((value < -1) || (value >= this.pSubItems.Count))
					throw new IndexOutOfRangeException();

				if (value != this.pSelectedIndex)
					this.pSelectedIndex = value;
			}
		}

		/// <summary>
		/// Gibt an, welche Untermenüpunkt ausgeklappt wurde oder legt diesen fest.
		/// </summary>
		public int CollapsedIndex
		{
			get { return this.pCollapsedIndex; }
			set
			{
				if ((value < -1) || (value >= this.pSubItems.Count))
					throw new IndexOutOfRangeException();

				if (value != this.pCollapsedIndex)
					this.pCollapsedIndex = value;
			}
		}

		/// <summary>
		/// Gibt an, ob dieser Menüpunkt der Knoten / Wurzel des Menübaumes ist.
		/// </summary>
		public bool Root { get { return true; } }

		/// <summary>
		/// Gibt den übergeordneten Knoten dieses Menüpunktes an.
		/// </summary>
		public IMenu<QuickMenuItem> PreviousLayer { get { return null; } }

		/// <summary>
		/// Gibt alle untergeordneten Menüpunkte an. Maximal können jedoch nur 6 Elemente angelegt werden.
		/// </summary>
		public List<QuickMenuItem> SubItems { get { return this.pSubItems; } }

		/// <summary>
		/// Gibt den ausgewählten Menüpunkt an.
		/// </summary>
		public QuickMenuItem SelectedItem { get { return (this.pSelectedIndex < 0) ? null : this.pSubItems[this.pSelectedIndex]; } }

		#endregion

		private void hideLayer ()
		{
			this.pHint.Visible = false;
			foreach (Button btn in this.pButtons)
				btn.Visible = false;
		}
		private void showLayer ()
		{
			this.setButtonProperties(true);
			if (this.pActiveMenu.SelectedIndex >= 0)
				this.pButtons[this.pActiveMenu.SelectedIndex].ActivateHoverEffect();

			this.pChangeLayer = false;
		}
		private void setButtonProperties (bool? Visible = null)
		{
			for (int i = 0; i < this.pActiveMenu.SubItems.Count; i++)
			{
				this.pButtons[i].Icon = this.pActiveMenu.SubItems[i].Icon;
				ButtonType type = (this.pActiveMenu.SubItems[i].Activated) ? ButtonType.QuickMenuSelected : ButtonType.QuickMenuStatic;
				this.pButtons[i].Texture = ContainerRessources.GetButtons(type)[i];
				this.pButtons[i].HoverTexture = ContainerRessources.GetButtons(ContainerRessources.Pendant(type))[i];

				this.pHint.Text = (this.pActiveMenu.SelectedItem == null)
					? string.Empty
					: this.pActiveMenu.SelectedItem.Text;

				if (Visible.HasValue)
				{
					this.pHint.Visible = Visible.Value;
					this.pButtons[i].Visible = Visible.Value;
				}
			}
		}

		/// <summary>
		/// Führt ein Update für diese und alle untergeordneten Komponenten aus.
		/// </summary>
		/// <param name="gameTime">Die Spielzeiteigenschaften.</param>
		public override void Update (GameTime gameTime)
		{
			if (this.pChangeLayer)
			{
				bool layerVisible = false;
				foreach (Button btn in this.pButtons)
					layerVisible |= btn.Visible;

				if (!layerVisible)
					this.showLayer();
			}

			if (this.pRefreshRequested)
				this.setButtonProperties();

			base.Update(gameTime);
		}

		/// <summary>
		/// Springt zum Hauptmenü und versteckt den zweiten Layer.
		/// </summary>
		public void JumpFirst ()
		{
			this.hideLayer();
			this.pActiveMenu.SelectedIndex = -1;
			this.pActiveMenu.CollapsedIndex = -1;
			this.pActiveMenu = this;
			this.pChangeLayer = true;
		}
		/// <summary>
		/// Selektiert den Nachfolger im  Menü.
		/// </summary>
		public void Next ()
		{
			if (this.pActiveMenu.SubItems.Count < 1)
				return;

			int buffer = this.pActiveMenu.SelectedIndex + 1;
			if (buffer >= this.pActiveMenu.SubItems.Count)
				buffer = 0;

			if (this.pActiveMenu.SelectedIndex >= 0)
				this.pButtons[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();

			this.pActiveMenu.SelectedIndex = buffer;
			this.pButtons[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();

			this.pHint.Text = (this.pActiveMenu.SelectedItem.Text == null)
				? string.Empty
				: this.pActiveMenu.SelectedItem.Text;
		}
		/// <summary>
		/// Selektiert den Vorgänger im Menü
		/// </summary>
		public void Previous ()
		{
			if (this.pActiveMenu.SubItems.Count < 1)
				return;

			int buffer = this.pActiveMenu.SelectedIndex - 1;
			if (buffer < 0)
				buffer = this.pActiveMenu.SubItems.Count - 1;

			if (this.pActiveMenu.SelectedIndex >= 0)
				this.pButtons[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();

			this.pActiveMenu.SelectedIndex = buffer;
			this.pButtons[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();

			this.pHint.Text = (this.pActiveMenu.SelectedItem.Text == null)
				? string.Empty
				: this.pActiveMenu.SelectedItem.Text;
		}
		/// <summary>
		/// Geht eine Ebene zurück.
		/// </summary>
		public void LayerBackward ()
		{
			if (this.pActiveMenu.Root)
				return;

			this.hideLayer();
			this.pActiveMenu.SelectedIndex = -1;
			this.pActiveMenu.CollapsedIndex = -1;
			this.pActiveMenu = this.pActiveMenu.PreviousLayer;
			this.pChangeLayer = true;
		}
		/// <summary>
		/// Führt die jeweilige Aktion aus, die für den aktuell ausgewählten Menüunterpunkt vorgesehen ist (wie ein Klick, Tastendruck etc.)
		/// </summary>
		public void PerformAction ()
		{
			if (this.pActiveMenu.SelectedItem == null)
				return;

			switch (this.pActiveMenu.SelectedItem.ActivationType)
			{
				case ActivationType.LayerForward:
					this.hideLayer();

					this.pActiveMenu.CollapsedIndex = this.pActiveMenu.SelectedIndex;
					this.pActiveMenu = this.pActiveMenu.SelectedItem;
					this.pActiveMenu.SelectedIndex = 0;
					this.pActiveMenu.CollapsedIndex = -1;

					this.pChangeLayer = true;

					break;

				case ActivationType.LayerBackward:
					this.LayerBackward();

					break;

				case ActivationType.OwnDelegate:
					QuickMenuItem subMenu = this.pActiveMenu.SelectedItem;
					subMenu.Action();

					break;

				case ActivationType.Activation:
					this.pActiveMenu.SelectedItem.Activated = !this.pActiveMenu.SelectedItem.Activated;
					if (this.pActiveMenu.SelectedItem.Action != null)
						this.pActiveMenu.SelectedItem.Action();

					this.Refresh();

					break;

				default:
					break;
			}
		}

		// Chooser
		private void choose (int index)
		{
			if (index < this.pActiveMenu.SubItems.Count)
			{
				if (this.pActiveMenu.SelectedIndex != index)
				{
					if (this.pActiveMenu.SelectedIndex >= 0)
						this.pButtons[this.pActiveMenu.SelectedIndex].ChangeHoverEffect();

					this.pButtons[index].ChangeHoverEffect();

					this.pActiveMenu.SelectedIndex = index;

					this.pHint.Text = (this.pActiveMenu.SelectedItem.Text == null)
						? string.Empty
						: this.pActiveMenu.SelectedItem.Text;
				}
			}
		}

		public void ChooseTop ()
		{
			this.choose(0);
		}

		public void ChooseTopRight ()
		{
			this.choose(1);
		}

		public void ChooseBottomRight ()
		{
			this.choose(2);
		}

		public void ChooseBottom ()
		{
			this.choose(3);
		}

		public void ChooseBottomLeft ()
		{
			this.choose(4);
		}

		public void ChooseTopLeft ()
		{
			this.choose(5);
		}




		/// <summary>
		/// Löst das Ergebnis VisisbleChanged aus.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnVisibleChanged (EventArgs e)
		{
			base.OnVisibleChanged(e);

			if (this.pSubItems.Count > 6)
				throw new System.InvalidOperationException("Quickmenü enthält mehr als 6 Objekte.");

			if (this.pVisible)
			{
				this.pActiveMenu = this;
				this.pActiveMenu.SelectedIndex = 0;

				this.showLayer();
			}
			else
			{
				this.pHint.Visible = false;
				foreach (Button btn in this.pButtons)
					btn.Visible = false;
			}
		}

		/// <summary>
		/// Selektiert diesen Menüpunkt.
		/// </summary>
		public void Select ()
		{
			throw new NotImplementedException();
		}
		/// <summary>
		/// Gibt den Wurzelknoten im Menübaum an.
		/// </summary>
		/// <returns></returns>
		public IMenu<QuickMenuItem> GetRoot ()
		{
			return this;
		}
	}

	/// <summary>
	/// Repräsentiert ein Menüpunkt.
	/// </summary>
	public class QuickMenuItem : IMenu<QuickMenuItem>
	{
		#region Fields

		private ActivationType pActionType;

		private string pText; // Anzeige - Text
		private IMenu<QuickMenuItem> pParent; // Übergeordnetes Menü
		private List<QuickMenuItem> pSubItems; // Untergeordnete Menüs

		private int pSelectedIndex; // Ausgewähltes Element
		private Action pOnAction;

		private int pCollapsedIndex;

		private bool pActivated;
		private Texture2D pIcon;

		#endregion

		public QuickMenuItem (IMenu<QuickMenuItem> Parent)
		{
			if (Parent == null)
				throw new ArgumentNullException();

			this.pSubItems = new List<QuickMenuItem>();
			this.pParent = Parent;
			this.pSelectedIndex = -1;
			this.pCollapsedIndex = -1;
		}

		/// <summary>
		/// Instanziiert ein neues Objekt dieser Klasse.
		/// </summary>
		/// <param name="Text">Label.</param>
		/// <param name="Parent">Übergeordneter Menüpunkt.</param>
		public QuickMenuItem (string Text, IMenu<QuickMenuItem> Parent)
			: this(Text, ActivationType.Activation, Parent)
		{ }
		/// <summary>
		/// Instanziiert ein neues Objekt dieser Klasse.
		/// </summary>
		/// <param name="Text">Label.</param>
		/// <param name="Type">Typ des Menüpunktes, der beim aktivieren unterschiedlich reagiert. (Siehe <see cref="ActivationType"/>)</param>
		/// <param name="Parent">Übergeordneter Menüpunkt.</param>
		public QuickMenuItem (string Text, ActivationType Type, IMenu<QuickMenuItem> Parent)
			: this(Parent)
		{
			if (Type == ActivationType.LayerForward)
			{
				QuickMenuItem item = new QuickMenuItem(" < Zurück < ", ActivationType.LayerBackward, this);
				item.Icon = ContainerRessources.GetIcons()[6];
				this.pSubItems.Add(item);
			}

			this.pText = Text;
			this.pActionType = Type;
			this.pOnAction = null;
		}
		/// <summary>
		/// Instanziiert ein neues Objekt dieser Klasse.
		/// </summary>
		/// <param name="Text">Label.</param>
		/// <param name="OnActivation">Auszuführende Aktion beim Aktivieren des Menüpunktes.</param>
		/// <param name="Parent">Übergeordneter Menüpunkt.</param>
		public QuickMenuItem (string Text, Action OnActivation, IMenu<QuickMenuItem> Parent)
			: this(Parent)
		{
			this.pText = Text;
			this.pActionType = ActivationType.OwnDelegate;
			this.pOnAction = OnActivation;
		}

		#region Properties

		/// <summary>
		/// Gibt an, ob der Menüpunkt aktiviert ist oder legt diese Eigenschaft fest.
		/// </summary>
		public bool Activated { get { return this.pActivated; } set { this.pActivated = value; } }
		/// <summary>
		/// Gibt das Icon für den Menüpunkt an oder legt es fest.
		/// </summary>
		public Texture2D Icon { get { return this.pIcon; } set { this.pIcon = value; } }
		/// <summary>
		/// Auszuführende Methode beim Aktivieren des Menüpunktes.
		/// </summary>
		public Action Action { get { return this.pOnAction; } set { this.pOnAction = value; } }
		/// <summary>
		/// Typ der Aktivierung.
		/// </summary>
		public ActivationType ActivationType { get { return this.pActionType; } set { this.pActionType = value; } }

		/// <summary>
		/// Gibt den Index dieses Menüpunktes gegenüber dem übergeordneten Menü an.
		/// </summary>
		public int Index
		{
			get
			{
				for (int i = 0; i < this.pSubItems.Count; i++)
					if (object.ReferenceEquals(this, this.pParent.SubItems[i]))
						return i;

				return -1;
			}
		}
		/// <summary>
		/// Gibt an, welcher Untermenüpunkt dieses Menüpunktes ausgewählt wurde oder legt diesen fest.
		/// </summary>
		public int SelectedIndex { get { return this.pSelectedIndex; } set { this.pSelectedIndex = value; } }
		/// <summary>
		/// Gibt an, welche Untermenüpunkt ausgeklappt wurde oder legt diesen fest.
		/// </summary>
		public int CollapsedIndex { get { return this.pCollapsedIndex; } set { this.pCollapsedIndex = value; } }

		/// <summary>
		/// Gibt an, ob dieser Menüpunkt der Knoten / Wurzel des Menübaumes ist.
		/// </summary>
		public bool Root { get { return false; } }
		/// <summary>
		/// Gibt den übergeordneten Knoten dieses Menüpunktes an.
		/// </summary>
		public IMenu<QuickMenuItem> PreviousLayer { get { return this.pParent; } }
		/// <summary>
		/// Gibt alle untergeordneten Menüpunkte an.
		/// </summary>
		public List<QuickMenuItem> SubItems { get { return this.pSubItems; } }

		/// <summary>
		/// Gibt den ausgewählten Menüpunkt an.
		/// </summary>
		public QuickMenuItem SelectedItem { get { return (this.pSelectedIndex < 0) ? null : this.pSubItems[this.pSelectedIndex]; } }

		/// <summary>
		/// Gibt den Text an, den dieser Menüpunkt darstellen soll oder legt diesen fest.
		/// </summary>
		public string Text { get { return this.pText; } set { this.pText = value; } }

		#endregion

		/// <summary>
		/// Selektiert diesen Menüpunkt.
		/// </summary>
		public void Select ()
		{
			throw new NotImplementedException();
		}
		/// <summary>
		/// Gibt den Wurzelknoten im Menübaum an.
		/// </summary>
		/// <returns></returns>
		public IMenu<QuickMenuItem> GetRoot ()
		{
			return this.pParent.GetRoot();
		}
	}
}
